﻿Imports Mystery

Public Class ContentsTable

    Private _first_time As Boolean = True
    Private _properties As IEnumerable(Of ContentProperty)
    Private _properties_controls_attr As ICollection(Of ContentPropertyColumnAttr) = New List(Of ContentPropertyColumnAttr)

    Private _content_type As ContentType

    Public Property new_content_filter As IContentFilter

    Public Property _column_filters As New List(Of IPropertyFilterControl)

    Private cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.


        AddHandler cd.contentAdded, Sub(content As IContent)
                                        If new_content_filter Is Nothing Then Exit Sub
                                        If Not new_content_filter.doesMatch(content) Then Exit Sub
                                        Me.AddContent(content)
                                    End Sub
        AddHandler cd.contentRemoved, Sub(content As IContent)
                                          Me.HideControls(content)
                                      End Sub

    End Sub

    Private Function getContents() As IEnumerable(Of IContent)
        Dim result As IEnumerable(Of IContent) = (From x As Guid In _contents_guids Select cd.getContent(Of IContent)(x))
        Return New List(Of IContent)(From x As IContent In result Select x Where x IsNot Nothing)
    End Function

    Private Sub FilterChanged()
        
        For Each c As IContent In getContents()
            HideOrShow(c)
        Next

    End Sub

    Public Sub generateControl(Of T As IContent)()
        Dim type As Type = GetType(T)

        _properties_controls_attr = New List(Of ContentPropertyColumnAttr)(getMystery.AssemblyRegister.getMysteryPropertyAttributes(Of ContentPropertyColumnAttr)((type)))
        _content_type = type.getMysteryAttribute(Of ContentType)()

        Dim index As Integer = 0
        Dim cd As ColumnDefinition

        For Each pc As ContentPropertyColumnAttr In _properties_controls_attr

            cd = New ColumnDefinition
            theGrid.ColumnDefinitions.Add(cd)

            Dim head_stak As New StackPanel
            Grid.SetRow(head_stak, 0)
            Grid.SetColumn(head_stak, index)
            theGrid.Children.Add(head_stak)

            Dim plabel As New Label
            plabel.Content = pc.label
            head_stak.Children.Add(plabel)

            Dim filter As UserControl = pc.instanceFilter
            If filter IsNot Nothing Then
                head_stak.Children.Add(filter)
                If TypeOf (filter) Is IPropertyFilterControl Then
                    Dim pfc As IPropertyFilterControl = filter
                    _column_filters.Add(pfc)
                    If Not String.IsNullOrEmpty(pfc.label) Then
                        plabel.Content = pfc.label
                    End If
                    AddHandler pfc.haveChanged, AddressOf FilterChanged
                End If

            End If

            index += 1
        Next

        _first_time = False

    End Sub

    Private _content_index As Integer = 1 'starting for 1 because row 0 is header

    Private _content_controls_map As New Dictionary(Of Guid, ICollection(Of IPropertyControl))
    Private _content_row_map As New Dictionary(Of Guid, RowDefinition)
    Private _contents_guids As New HashSet(Of Guid)
    Private _content_subcriber_map As New Dictionary(Of Guid, IContentModificationsSubriver)


    Private Sub ShowControls(content As IContent)
        If content Is Nothing Then Exit Sub
        If Not _content_controls_map.ContainsKey(content.guid) Then Exit Sub
        Dim controls As IEnumerable(Of IPropertyControl) = _content_controls_map(content.guid)

        For Each pc As IPropertyControl In controls
            pc.content = content
            If TypeOf (pc) Is UserControl Then
                Dim c As UserControl = pc
                c.Visibility = Windows.Visibility.Visible
            End If
        Next
        _content_row_map(content.guid).Height = New GridLength
    End Sub

    Private Sub HideControls(content As IContent)
        If content Is Nothing Then Exit Sub
        If Not _content_controls_map.ContainsKey(content.guid) Then Exit Sub
        Dim controls As IEnumerable(Of IPropertyControl) = _content_controls_map(content.guid)

        For Each pc As IPropertyControl In controls
            pc.content = content
            If TypeOf (pc) Is UserControl Then
                Dim c As UserControl = pc
                c.Visibility = Windows.Visibility.Hidden
            End If
        Next
        _content_row_map(content.guid).Height = New GridLength(0)
    End Sub


    Private Function ShouldBeShowen(content As IContent) As Boolean
        If new_content_filter IsNot Nothing AndAlso Not new_content_filter.doesMatch(content) Then Return False
        For Each ccf As IPropertyFilterControl In _column_filters
            If Not ccf.Match(content) Then Return False
        Next
        Return True
    End Function

    Private Sub HideOrShow(content As IContent)
        Me.Dispatcher.Invoke(Sub()
                                 Dim stil_visible As Boolean = ShouldBeShowen(content)
                                 If stil_visible Then
                                     ShowControls(content)
                                 Else
                                     HideControls(content)
                                 End If
                             End Sub)
    End Sub

    'terrible dubt then this may reset all content in table to the state where they first got in
    'Private Sub ControlChangeValue(control As IPropertyControl)
    '    Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
    '    Dim contents As IEnumerable(Of IContent) = control.setInContent()
    '    cd.addContents(contents)
    'End Sub

    Public Sub AddContent(content As IContent)
        If content Is Nothing Then Exit Sub
        Dim content_guid As Guid = content.guid
        If _contents_guids.Contains(content_guid) Then Exit Sub
        _content_controls_map(content_guid) = New LinkedList(Of IPropertyControl)
        Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
        _content_subcriber_map(content_guid) = New BaseContentModificationsSubriver(content, Sub() HideOrShow(cd.getContent(Of IContent)(content_guid)))
        Dim cm As ContentModifications = getGlobalObject(Of ContentModifications)()
        cm.subscrive(_content_subcriber_map(content_guid))

        _contents_guids.Add(content_guid)

        Dim rd As New RowDefinition
        theGrid.RowDefinitions.Add(rd)
        _content_row_map(content_guid) = rd

        Dim property_index As Integer = 0

        For Each pc As ContentPropertyColumnAttr In _properties_controls_attr
            Dim c As UserControl = pc.createControl(content)
            Grid.SetRow(c, _content_index)
            Grid.SetColumn(c, property_index)

            theGrid.Children.Add(c)

            If TypeOf (c) Is IPropertyControl Then
                Dim property_control As IPropertyControl = c
                _content_controls_map(content.guid).Add(property_control)
                'AddHandler property_control.valueChanged, Sub() ControlChangeValue(property_control)
            End If
            property_index += 1
        Next
        _content_index += 1


        If ShouldBeShowen(content) Then
            ShowControls(content)
        Else
            HideControls(content)
        End If

    End Sub

    Public Sub showContents(contents As IEnumerable(Of IContent))


        For Each content As IContent In contents
            AddContent(content)
        Next

    End Sub

    Public Sub refresh(contents As IEnumerable(Of IContent))
        For Each c As IContent In contents
            Me.AddContent(c) 'if not yet give it will be added
            Me.HideOrShow(c)
        Next
    End Sub


    
End Class
